/**
 *    Copyright 2009-2018 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package com.yinsin.jpabatis.executor.resultset;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.yinsin.jpabatis.config.Configuration;
import com.yinsin.jpabatis.exceptions.JpaBatisException;
import com.yinsin.jpabatis.io.Resources;
import com.yinsin.jpabatis.mapper.ResultMap;
import com.yinsin.jpabatis.mapper.ResultMapping;
import com.yinsin.jpabatis.type.JdbcType;
import com.yinsin.jpabatis.type.TypeConvert;
import com.yinsin.jpabatis.util.BeanUtils;

/**
 * @author Iwao AVE!
 */
public class ResultSetWrapper {

	private final Map<String, String> propertyNames = new HashMap<>();
	private final List<String> columnNames = new ArrayList<>();
	private final Map<String, String> classNames = new HashMap<>();
	private final Map<String, JdbcType> jdbcTypes = new HashMap<>();
	private final Map<String, Object> valueMap = new HashMap<>();
	private static final String SPLIT = "_";
	private static final String SET = "set";

	public ResultSetWrapper(Map<String, Object> result, Configuration configuration, ResultMap resultMap) throws JpaBatisException {
		super();
		ResultMapping mapping = null;
		JdbcType type = null;
		String className = null, propertyName;
		for (Map.Entry<String, Object> entry : result.entrySet()) {
			columnNames.add(entry.getKey());
			mapping = resultMap.getResultMapping(entry.getKey());
			if (null != mapping) {
				propertyName = mapping.getProperty();
				className = BeanUtils.getJavaType(mapping.getJdbcType().name());
				type = mapping.getJdbcType();
			} else {
				propertyName = columnToProperty(entry.getKey());
				if (null != entry.getValue()) {
					className = entry.getValue().getClass().getName();
					type = JdbcType.forCode(TypeConvert.forClass(entry.getValue().getClass()));
				} else {
					className = Object.class.getSimpleName();
					type = JdbcType.forCode(TypeConvert.forClass(Object.class));
				}
			}
			propertyNames.put(entry.getKey(), propertyName);
			classNames.put(entry.getKey(), className);
			jdbcTypes.put(entry.getKey(), type);
			valueMap.put(entry.getKey(), entry.getValue());
		}
	}

	private String columnToProperty(String columnName) {
		String property = columnName;
		if (columnName != null && !columnName.isEmpty()) {
			if (columnName.indexOf(SPLIT) != -1) {
				String[] strs = columnName.split(SPLIT);
				for (int i = 0; i < strs.length; i++) {
					if (strs[i] != null && strs[i].length() > 0) {
						property += firstCharToUpperCase(strs[i]);
					}
				}
			} else {
				property = firstCharToUpperCase(columnName);
			}
			if (property.matches("[A-Z]+")) {
				property = firstCharToUpperCase(property.toLowerCase());
			}
		}
		return property;
	}
	
	private String firstCharToUpperCase(String content) {
        if (null != content && !content.isEmpty()) {
            String tou = content.substring(0, 1);
            String wei = content.substring(1);
            content = tou.toUpperCase() + wei;
        }
        return content;
    }
	
	public List<String> getColumnNames() {
		return this.columnNames;
	}

	public JdbcType getJdbcType(String columnName) {
		return jdbcTypes.get(columnName);
	}
	
	public String getMethodName(String columnName) {
		return SET + firstCharToUpperCase(propertyNames.get(columnName));
	}
	
	public String getProperty(String columnName) {
		return propertyNames.get(columnName);
	}

	public Class<?> getJavaType(String columnName) throws ClassNotFoundException {
		return Resources.classForName(classNames.get(columnName));
	}
	
	public Object getValue(String columnName, Class<?> classz) {
		Object value = valueMap.get(columnName);
		if(null != value){
			return BeanUtils.coventValue(value, classz);
		}
		return value;
	}

	public Object getResultObject(){
		return valueMap;
	}
	
}
